package drds.server.config;

import java.io.IOException;
import java.net.StandardSocketOptions;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Map;

import drds.server.api_warpper.Lock;
import drds.server.config.cluster.Cluster;
import drds.server.config.model.DRDS;
import drds.server.config.model.Schema;
import drds.server.config.model.User;
import drds.server.datasource.GroupDataSource;
import drds.server.datasource.GroupDataSourceNode;
import drds.server.net.ISessionContext;
import drds.server.util.CurrentTimeMillis;

/**
 * 
 * @author 曹正辉<330937205@qq.com>
 */
public class Config {

	private static final int RELOAD = 1;
	private static final int ROLLBACK = 2;
	private static final int RELOAD_ALL = 3;

	private volatile DRDS systemConfig;
	private volatile Cluster cluster;
	private volatile Cluster _cluster;
	private volatile Map<String, User> userInfoMap;
	private volatile Map<String, User> _userInfoMap;
	private volatile Schema schema;
	private volatile Schema _schema;
	private volatile Map<String, GroupDataSourceNode> groupDataSourceNodeMap;
	private volatile Map<String, GroupDataSourceNode> _groupDataSourceNodeMap;
	private volatile Map<String, GroupDataSource> groupDataSourceMap;
	private volatile Map<String, GroupDataSource> _groupDataSourceMap;
	private long reloadTime;
	private long rollbackTime;
	private int status;
	private final Lock lock;

	public Config() {

		// 读取schema.xml，rule.xml和server.xml
		ConfigInitializer configInitializer = new ConfigInitializer(true);
		this.systemConfig = configInitializer.getSystemConfig();
		this.userInfoMap = configInitializer.getUserMap();
		this.schema = configInitializer.getSchema();
		this.groupDataSourceMap = configInitializer.getDataHosts();

		this.groupDataSourceNodeMap = configInitializer.getGroupDataSourceNodeMap();
		for (GroupDataSource groupDataSource : groupDataSourceMap.values()) {
			groupDataSource.setSchemas(getDataNodeSchemasOfDataHost(groupDataSource.getHostName()));
		}

		this.cluster = configInitializer.getCluster();

		// 初始化重加载配置时间
		this.reloadTime = CurrentTimeMillis.currentTimeMillis();
		this.rollbackTime = -1L;
		this.status = RELOAD;

		// 配置加载锁
		this.lock = new Lock();
	}

	public DRDS getDRDS() {
		return systemConfig;
	}

	public void setSocketParams(ISessionContext sessionContext) throws IOException {

		int socketsorcvbuf = 0;
		int socketsosndbuf = 0;
		int socketNoDelay = 0;
		socketsorcvbuf = systemConfig.getSocketsorcvbuf();
		socketsosndbuf = systemConfig.getSocketsosndbuf();
		socketNoDelay = systemConfig.getSocketNoDelay();

		SocketChannel socketChannel = sessionContext.getSocketChannel();
		socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, socketsorcvbuf);
		socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, socketsosndbuf);
		socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, socketNoDelay == 1);
		socketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
		socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);

		sessionContext.setMaxPacketSize(systemConfig.getMaxPacketSize());
		sessionContext.setPacketHeaderSize(systemConfig.getPacketHeaderSize());
		sessionContext.setIdleTimeout(systemConfig.getIdleTimeout());

	}

	public Map<String, User> getUsers() {
		return userInfoMap;
	}

	public Map<String, User> getBackupUsers() {
		return _userInfoMap;
	}

	public Map<String, GroupDataSourceNode> getGroupDataSourceNodeMap() {
		return groupDataSourceNodeMap;
	}

	public void setDataNodes(Map<String, GroupDataSourceNode> map) {
		this.groupDataSourceNodeMap = map;
	}

	public String[] getDataNodeSchemasOfDataHost(String dataHost) {
		ArrayList<String> schemas = new ArrayList<String>(30);
		for (GroupDataSourceNode groupDataSourceNode : groupDataSourceNodeMap.values()) {
			if (groupDataSourceNode.getGroupDataSource().getHostName().equals(dataHost)) {
				schemas.add(groupDataSourceNode.getSchemaName());
			}
		}
		return schemas.toArray(new String[schemas.size()]);
	}

	public Map<String, GroupDataSourceNode> getBackupGroupDataSourceMap() {
		return _groupDataSourceNodeMap;
	}

	public Map<String, GroupDataSource> getGroupDataSourceMap() {
		return groupDataSourceMap;
	}

	public Map<String, GroupDataSource> getBackupDataHosts() {
		return _groupDataSourceMap;
	}

	public Cluster getCluster() {
		return cluster;
	}

	public Cluster getBackupCluster() {
		return _cluster;
	}

	public Lock getLock() {
		return lock;
	}

	public long getReloadTime() {
		return reloadTime;
	}

	public long getRollbackTime() {
		return rollbackTime;
	}

	public void reload(Map<String, User> users, Map<String, Schema> schemas, Map<String, GroupDataSourceNode> dataNodes, Map<String, GroupDataSource> dataHosts, Cluster cluster, boolean reloadAll) {

		apply(users, schemas, dataNodes, dataHosts, cluster, reloadAll);
		this.reloadTime = CurrentTimeMillis.currentTimeMillis();
		this.status = reloadAll ? RELOAD_ALL : RELOAD;
	}

	public boolean canRollback() {
		if (_userInfoMap == null || _schema == null || _groupDataSourceNodeMap == null || _groupDataSourceMap == null || _cluster == null || status == ROLLBACK) {
			return false;
		} else {
			return true;
		}
	}

	public void rollback(Map<String, User> users, Map<String, Schema> schemas, Map<String, GroupDataSourceNode> dataNodes, Map<String, GroupDataSource> dataHosts, Cluster cluster) {

		apply(users, schemas, dataNodes, dataHosts, cluster, status == RELOAD_ALL);
		this.rollbackTime = CurrentTimeMillis.currentTimeMillis();
		this.status = ROLLBACK;
	}

	private void apply(Map<String, User> users, Map<String, Schema> schemaMap, Map<String, GroupDataSourceNode> groupDataSourceNodeMap, Map<String, GroupDataSource> groupDataSourceMap, Cluster cluster, boolean isLoadAll) {

		final Lock lock = this.lock;
		lock.lock();
		try {

			// old 处理
			// 1、停止老的数据源心跳
			// 2、备份老的数据源配置
			// --------------------------------------------
			if (isLoadAll) {
				Map<String, GroupDataSource> oldGroupDataSourceMap = this.groupDataSourceMap;
				if (oldGroupDataSourceMap != null) {
					for (GroupDataSource oldGroupDataSource : oldGroupDataSourceMap.values()) {
						if (oldGroupDataSource != null) {
							// oldDbPool.stopHeartbeat();
						}
					}
				}
				this._groupDataSourceNodeMap = this.groupDataSourceNodeMap;
				this._groupDataSourceMap = this.groupDataSourceMap;
			}

			this._userInfoMap = this.userInfoMap;
			this._schema = this.schema;
			this._cluster = this.cluster;

			// new 处理
			// 1、启动新的数据源心跳
			// 2、执行新的配置
			// ---------------------------------------------------
			if (isLoadAll) {
				if (groupDataSourceNodeMap != null) {
					for (GroupDataSource newDbPool : groupDataSourceMap.values()) {
						if (newDbPool != null) {
							// newDbPool.startHeartbeat();
						}
					}
				}
				this.groupDataSourceNodeMap = groupDataSourceNodeMap;
				this.groupDataSourceMap = groupDataSourceMap;
			}
			this.userInfoMap = users;
			this.schema = schema;
			this.cluster = cluster;

		} finally {
			lock.unlock();
		}
	}

	public Schema getSchema() {
		// TODO Auto-generated method stub
		return null;
	}
}